import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class ReflectionApplication {
    public static void main(String[] args) {
        try {
            // 1. Class对象获取演示
            classObjectDemo();

            // 2. 字段操作演示
            fieldOperationDemo();

            // 3. 方法调用演示
            methodInvocationDemo();

            // 4. 构造器使用演示
            constructorDemo();

            // 5. 反射实际应用：对象拷贝，数据映射
            practicalApplicationDemo();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Class对象获取演示
     */
    private static void classObjectDemo() throws ClassNotFoundException {
        System.out.println("=== Class对象获取演示 ===");

        // 方式1：类名.class（编译时确定）
        Class<String> clazz1 = String.class;
        System.out.println("方式1 - 类名.class: " + clazz1.getName());

        // 方式2：对象.getClass()（运行时获取）
        String str = "Hello";
        Class<?> clazz2 = str.getClass();
        System.out.println("方式2 - 对象.getClass(): " + clazz2.getName());

        // 方式3：Class.forName()（动态加载）
        Class<?> clazz3 = Class.forName("java.lang.String");
        System.out.println("方式3 - Class.forName(): " + clazz3.getName());

        // 验证是同一个Class对象
        System.out.println("三种方式获取的是同一个对象: " +
                (clazz1 == clazz2 && clazz2 == clazz3));

        // 获取类的基本信息
        System.out.println("类的简单名称: " + clazz1.getSimpleName());
        System.out.println("类的包名: " + clazz1.getPackage().getName());
        System.out.println("父类: " + clazz1.getSuperclass().getName());
        System.out.println("实现的接口: " + Arrays.toString(clazz1.getInterfaces()));

        System.out.println();
    }

    /**
     * 字段操作演示
     */
    private static void fieldOperationDemo() throws Exception {
        System.out.println("=== 字段操作演示 ===");

        // 创建测试对象
        Person person = new Person("张三", 25, "秘密");
        Class<?> clazz = person.getClass();

        // 获取所有字段（包括私有字段）
        Field[] fields = clazz.getDeclaredFields();
        System.out.println("所有字段:");
        for (Field field : fields) {
            System.out.println("  " + field.getName() + " - " + field.getType().getSimpleName());
        }

        // 操作公共字段
        Field nameField = clazz.getDeclaredField("name");
        System.out.println("原始姓名: " + nameField.get(person));
        nameField.set(person, "李四");
        System.out.println("修改后姓名: " + nameField.get(person));

        // 操作私有字段
        Field secretField = clazz.getDeclaredField("secret");
        secretField.setAccessible(true);  // 绕过访问控制
        System.out.println("私有字段值: " + secretField.get(person));
        secretField.set(person, "新秘密");
        System.out.println("修改后私有字段: " + secretField.get(person));

        System.out.println();
    }

    /**
     * 方法调用演示
     */
    private static void methodInvocationDemo() throws Exception {
        System.out.println("=== 方法调用演示 ===");

        Person person = new Person("王五", 30, "隐私");
        Class<?> clazz = person.getClass();

        // 获取所有方法
        Method[] methods = clazz.getDeclaredMethods();
        System.out.println("所有方法:");
        for (Method method : methods) {
            System.out.println("修饰符" + method.getModifiers() + " " + method.getReturnType() + "  " + method.getName() +
                    "(" + Arrays.toString(method.getParameterTypes()) + ")");
        }

        // 调用无参方法
        Method toStringMethod = clazz.getMethod("toString");
        String result = (String) toStringMethod.invoke(person);
        System.out.println("toString()结果: " + result);

        // 调用有参方法
        Method setAgeMethod = clazz.getMethod("setAge", int.class);
        setAgeMethod.invoke(person, 35);
        System.out.println("设置年龄后: " + person);

        // 调用私有方法
        Method privateMethod = clazz.getDeclaredMethod("getSecret");
        privateMethod.setAccessible(true);
        String secret = (String) privateMethod.invoke(person);
        System.out.println("私有方法返回: " + secret);

        // 调用静态方法
        Method staticMethod = clazz.getDeclaredMethod("getSpecies");
        String species = (String) staticMethod.invoke(null);  // 静态方法传null
        System.out.println("静态方法返回: " + species);

        System.out.println();
    }

    /**
     * 构造器使用演示
     */
    private static void constructorDemo() throws Exception {
        System.out.println("=== 构造器使用演示 ===");

        Class<?> clazz = Person.class;

        // 获取所有构造器
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        System.out.println("所有构造器:");
        for (Constructor<?> constructor : constructors) {
            System.out.println("  " + constructor.getName() +
                    "(" + Arrays.toString(constructor.getParameterTypes()) + ")");
        }

        // 使用无参构造器
        Constructor<?> defaultConstructor = clazz.getDeclaredConstructor();
        Person person1 = (Person) defaultConstructor.newInstance();
        System.out.println("无参构造器创建: " + person1);

        // 使用有参构造器
        Constructor<?> paramConstructor = clazz.getDeclaredConstructor(
                String.class, int.class, String.class);
        Person person2 = (Person) paramConstructor.newInstance("赵六", 28, "机密");
        System.out.println("有参构造器创建: " + person2);

        System.out.println();
    }

    /**
     * 反射实际应用演示
     */
    private static void practicalApplicationDemo() throws Exception {
        System.out.println("=== 反射实际应用演示 ===");

        // 1. 简单的依赖注入容器
        SimpleContainer container = new SimpleContainer();
        container.register("userService", UserService.class);
        container.register("userDao", UserDao.class);

        UserService userService = (UserService) container.getInstance("userService");
        userService.saveUser("测试用户");

        // 2. 简单的对象映射器
        Map<String, Object> data = new HashMap<>();
        data.put("name", "映射测试");
        data.put("age", 25);
        data.put("secret", "映射秘密");

        Person mappedPerson = ObjectMapper.mapToPerson(data);
        System.out.println("映射结果: " + mappedPerson);

        System.out.println();
    }
}

/**
 * 测试用的Person类
 */
class Person {
    public String name;
    public int age;
    private String secret;

    public Person() {
        this("默认姓名", 0, "默认秘密");
    }

    public Person(String name, int age, String secret) {
        this.name = name;
        this.age = age;
        this.secret = secret;
    }

    public void setAge(int age) {
        this.age = age;
    }

    private String getSecret() {
        return secret;
    }

    public static String getSpecies() {
        return "Homo sapiens";
    }

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }
}

/**
 * 简单的依赖注入容器
 */
class SimpleContainer {
    private Map<String, Class<?>> services = new HashMap<>();
    private Map<String, Object> instances = new HashMap<>();

    public void register(String name, Class<?> clazz) {
        services.put(name, clazz);
    }

    public Object getInstance(String name) throws Exception {
        if (instances.containsKey(name)) {
            return instances.get(name);
        }

        Class<?> clazz = services.get(name);
        if (clazz == null) {
            throw new IllegalArgumentException("Service not found: " + name);
        }

        Object instance = clazz.getDeclaredConstructor().newInstance();
        instances.put(name, instance);
        return instance;
    }
}

/**
 * 用户服务类
 */
class UserService {
    public void saveUser(String username) {
        System.out.println("保存用户: " + username);
    }
}

/**
 * 用户数据访问类
 */
class UserDao {
    public void save(String data) {
        System.out.println("保存数据: " + data);
    }
}

/**
 * 简单的对象映射器
 */
class ObjectMapper {
    public static Person mapToPerson(Map<String, Object> data) throws Exception {
        Person person = new Person();
        Class<?> clazz = person.getClass();

        for (Map.Entry<String, Object> entry : data.entrySet()) {
            String fieldName = entry.getKey();
            Object value = entry.getValue();

            try {
                Field field = clazz.getDeclaredField(fieldName);
                field.setAccessible(true);
                field.set(person, value);
            } catch (NoSuchFieldException e) {
                System.out.println("字段不存在: " + fieldName);
            }
        }

        return person;
    }
}
